package controller

import (
	"context"
	Users "develop_user/contract/user"
	"develop_user/model"
	"develop_user/proto/user"
	"develop_user/utils"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-redis/redis/v8"
	"github.com/go-resty/resty/v2"
	"log"
	"math/big"
	"net/http"
	"strings"
	"time"
)

type User struct{}

func (u *User) UserRegister(ctx context.Context, in *user.UserRequest, out *user.UserResponse) error {
	//检查code是否匹配
	client := redis.NewClient(&redis.Options{
		Addr:     "43.138.147.44:6379", //redis数据库地址
		Password: "030903",             //redis数据库auth密码
		DB:       0,                    //redis db0 数据库
	})

	result := client.Get(context.TODO(), in.User)
	code, _ := result.Result()
	if code == in.Code { //代表code是合理的
		//第一个参数为合约地址
		newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
		if err != nil {
			//0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55
			log.Println("failed to use contract:", err.Error())
		}
		_, receipt, err := newUser.Register(utils.Instance.GetTransactOpts(), in.User, in.Password)
		log.Println(receipt.GetErrorMessage()) //err
		if err != nil {
			out.Code = 500
			out.Message = "failed to register"
			return err
		}
		if receipt.GetErrorMessage() != "" { //如果报错的话 就代表合约调用有错误
			out.Code = 500
			out.Message = receipt.GetErrorMessage()
			return errors.New(receipt.GetErrorMessage()) //set error
		}
		out.Code = 200
		out.Message = "register success"
		return nil
	} else {
		out.Code = 500
		out.Message = "验证码错误"
		return nil
	}
}

func (u *User) UserLogin(ctx context.Context, in *user.UserRequest, out *user.UserResponse) error {
	newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
	if err != nil {
		log.Println("failed to use contract:", err.Error())
	}
	flag, err := newUser.Login(utils.Instance.GetCallOpts(), in.User, in.Password)
	if err != nil {
		out.Code = 500
		out.Message = fmt.Sprint(err)
		return err
	}
	//代表登陆失败
	if !flag {
		out.Code = 500
		out.Message = "failed to login"
		return errors.New("failed to login")
	}
	out.Code = 200
	out.Message = "login success"
	return nil
}

func (u *User) SendEmail(ctx context.Context, in *user.SendEmailRequest, out *user.UserResponse) error {
	//拿到邮箱之后生成六位数随机数
	code := utils.GenEmailCode(6)
	//将邮箱作为键 验证码作为值 过期时间为60分钟 进行储存
	client := redis.NewClient(&redis.Options{
		Addr:     "43.138.147.44:6379", //redis数据库地址
		Password: "030903",             //redis数据库auth密码
		DB:       0,                    //redis db0 数据库
	})
	result := client.Set(context.TODO(), in.Email, code, time.Minute*60) //60分钟过期
	_, err := result.Result()
	if err != nil { //数据库储存失败
		out.Code = 500
		out.Message = "邮箱发送失败"
		return err
	}
	sprintf := fmt.Sprintf("您的验证码为: %s 该验证码一小时内有效", code)
	utils.SendEmail(in.Email, sprintf) //进行邮箱发送

	out.Code = 200
	out.Message = "邮箱发送成功"

	return nil
}

func (u *User) FindUser(ctx context.Context, in *user.FindUserRequest, out *user.UserResponse) error {
	//检查code是否匹配
	client := redis.NewClient(&redis.Options{
		Addr:     "43.138.147.44:6379", //redis数据库地址
		Password: "030903",             //redis数据库auth密码
		DB:       0,                    //redis db0 数据库
	})

	result := client.Get(context.TODO(), in.Email)
	code, _ := result.Result()
	if code == in.Code { //验证码正确
		//第一个参数为合约地址
		newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
		if err != nil {
			log.Println("failed to use contract:", err.Error())
		}
		_, _, err = newUser.ResetUser(utils.Instance.GetTransactOpts(), in.Email, in.Pass)
		if err != nil { //密码重置失败
			out.Code = 500
			out.Message = "密码重置失败"
			return err
		}
		out.Code = 200
		out.Message = "密码重置成功"
		return nil
	}
	out.Code = 500
	out.Message = "验证码不正确"
	return nil
}

func (u *User) GiteeUserAuth(ctx context.Context, in *user.UserAuthRequest, out *user.UserAuthResponse) error {
	//使用code去获取token
	//申请token
	sprintf := fmt.Sprintf("https://gitee.com/oauth/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s", model.Gitee_client_id, model.Gitee_client_secret, in.Token, model.Gitee_url)

	client := resty.New()

	get, err := client.R().Post(sprintf)
	if err != nil {
		log.Println("failed to client:", err)
	}
	var token model.Token
	err = json.Unmarshal([]byte(get.String()), &token)
	if err != nil {
		log.Println("failed to parse:", err.Error())
	}
	s := fmt.Sprintf("https://gitee.com/api/v5/user?access_token=%s", token.AccessToken)

	response, err := client.R().Get(s)
	if err != nil {
		log.Println("failed to get user info:", err.Error())
	}

	// 将响应的数据写入 userInfo 中，并返回
	var userInfo = model.JsonData{}

	log.Println(userInfo)

	reader := strings.NewReader(response.String())
	//将响应的数据 以mapping集合来排列
	json.NewDecoder(reader).Decode(&userInfo)

	//判断用户是否使用gitte登陆过

	//创建实例对象
	newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
	//0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55
	if err != nil {
		out.Code = 500
		out.Message = "获取用户信息失败"
		return err
	}

	login, _ := newUser.Login(utils.Instance.GetCallOpts(), userInfo.Login, string(userInfo.Id))
	if login { //证明以前创建过 不需要注册 直接登陆
		out.Code = 200
		out.Message = "用户登陆成功"
		out.Username = userInfo.Login //将用户的username传过去
	} else { //以前没有创建过 需要注册
		_, _, err = newUser.Register(utils.Instance.GetTransactOpts(), userInfo.Login, string(userInfo.Id))
		if err != nil {
			out.Code = 500
			out.Message = "获取用户信息失败"
			return err
		}
		//直接登陆成功
		out.Code = 200
		out.Message = "用户登陆成功"
		out.Username = userInfo.Login //将用户的username传过去
	}
	return nil
}

func (u *User) GithubUserAuth(ctx context.Context, in *user.UserAuthRequest, out *user.UserAuthResponse) error {
	sprintf := fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", model.Github_client_id, model.Github_client_secret, in.Token)

	req, err := http.NewRequest(http.MethodGet, sprintf, nil)

	if err != nil {
		log.Println("failed to get token:", err.Error())
	}

	req.Header.Set("accept", "application/json")

	// 发送请求并获得响应
	var httpClient = http.Client{}

	//获取token
	res, err := httpClient.Do(req)
	if err != nil {
		log.Println("err:", err.Error())
	}
	var token model.Token
	// 将token文件解析成json格式
	if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
		log.Println(err)
	}

	//通过token去获取用户信息
	var userInfoUrl = "https://api.github.com/user" // github用户信息获取接口

	req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil)

	req.Header.Set("accept", "application/json")

	req.Header.Set("Authorization", fmt.Sprintf("token %s", token.AccessToken))

	// 发送请求并获取响应
	var client = http.Client{}

	//发送请求
	res, err = client.Do(req)

	// 将响应的数据写入 userInfo 中，并返回
	var userInfo = make(map[string]interface{})

	//将响应的数据 以mapping集合来排列
	err = json.NewDecoder(res.Body).Decode(&userInfo)

	marshal, _ := json.Marshal(userInfo)

	var userInfos = model.JsonData{}

	reader := strings.NewReader(string(marshal))
	//将响应的数据 以mapping集合来排列
	json.NewDecoder(reader).Decode(&userInfos)

	//创建实例对象
	newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
	//0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55
	if err != nil {
		out.Code = 500
		out.Message = "获取用户信息失败"
		return err
	}

	login, err := newUser.Login(utils.Instance.GetCallOpts(), userInfos.Login, string(userInfos.Id))
	if err != nil {
		out.Code = 500
		out.Message = "获取用户信息失败"
		return err
	}
	if login { //证明以前创建过 不需要注册 直接登陆
		out.Code = 200
		out.Message = "用户登陆成功"
		out.Username = userInfos.Login //将用户的username传过去
	} else { //以前没有创建过 需要注册

		_, _, err = newUser.Register(utils.Instance.GetTransactOpts(), userInfos.Login, string(userInfos.Id))
		if err != nil {
			out.Code = 500
			out.Message = "获取用户信息失败"
			return err
		}
		//直接登陆成功
		out.Code = 200
		out.Message = "用户登陆成功"
		out.Username = userInfos.Login //将用户的username传过去
	}
	return nil
}

func (u *User) UserFeedback(ctx context.Context, in *user.UserFeedbackRequest, out *user.UserResponse) error {
	var info model.FeedBack
	info.Email = in.User
	info.FeedBackInfo = in.Feedback
	info.FeedBackGoods = in.OrderInfo

	result := utils.Db.Create(&info)
	if result.Error != nil { //用户反馈失败
		out.Code = 500
		out.Message = "用户反馈失败"
		return result.Error
	}

	out.Code = 200
	out.Message = "用户反馈成功"
	return nil
}

func (u *User) GetUserAccount(ctx context.Context, in *user.GetUserAccountRequest, out *user.GetUserAccountResponse) error {
	newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
	if err != nil {
		out.Code = 500
		out.Msg = "获取用户余额失败"
		return err
	}

	num, err := newUser.BalanceOf(utils.Instance.GetCallOpts(), in.User)
	if err != nil {
		out.Code = 500
		out.Msg = "获取用户余额失败"
		return err
	}

	out.Code = 200
	out.Msg = "获取用户余额成功"
	out.Num = utils.StrToInt(num.String())
	return nil
}

func (u *User) UserMint(ctx context.Context, in *user.UserMintRequest, out *user.UserResponse) error {
	newUser, err := Users.NewUser(common.HexToAddress("0x37adf14f4ebbd2eb6254c8bd04eed49731b2fe55"), utils.Instance)
	if err != nil {
		out.Code = 500
		out.Message = "充值失败"
		return err
	}

	num := big.NewInt(int64(in.Num))

	_, _, err = newUser.Mint(utils.Instance.GetTransactOpts(), in.User, num)
	if err != nil {
		out.Code = 500
		out.Message = "充值失败"
		return err
	}

	out.Code = 200
	out.Message = "充值成功"
	return nil
}
